/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.common.util;

import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.security.CodeSource;
import java.util.Properties;

/**
 * class path 资源加载工具类
 *
 * @author vacoor
 */
@SuppressWarnings("unused")
public abstract class Resources {

    public static URL getResource(String res) {
        return getResource(null, res);
    }

    public static URL getResource(ClassLoader classLoader, String res) {
        res = res.startsWith("/") ? res.substring(1) : res;
        ClassLoader cl = null != classLoader ? classLoader : Thread.currentThread().getContextClassLoader();
        cl = null != cl ? cl : Resources.class.getClassLoader();

        return cl.getResource(res);
    }

    public static File getResourceAsFile(String res) {
        return getResourceAsFile(null, res);
    }

    /**
     * 读取文件, 失败或不存在返回null
     */
    public static File getResourceAsFile(ClassLoader cl, String res) {
        final URL url = getResource(cl, res);
        try {
            return url != null ? new File(url.toURI()) : null;
        } catch (URISyntaxException e) {
            return null;
        }
    }

    public static Properties getResourceAsProperties(String res) {
        return getResourceAsProperties(null, res);
    }

    /**
     * 读取 properties 文件, 如果失败返回 null
     */
    public static Properties getResourceAsProperties(ClassLoader cl, String res) {
        Reader reader = getResourceAsReader(cl, res);
        if (null == reader) {
            return null;
        }
        try {
            Properties props = new Properties();
            props.load(reader);

            return props;
        } catch (IOException ignore) {
        }
        return null;
    }

    public static InputStream getResourceAsStream(String res) {
        return getResourceAsStream(null, res);
    }

    /**
     * 读取资源作为流, 如果失败返回 null
     */
    public static InputStream getResourceAsStream(ClassLoader cl, String res) {
        final URL url = getResource(cl, res);
        try {
            return url != null ? url.openStream() : null;
        } catch (IOException e) {
            return null;
        }
    }

    public static Reader getResourceAsReader(String res) {
        return getResourceAsReader(null, res);
    }

    public static Reader getResourceAsReader(ClassLoader cl, String res) {
        InputStream is = getResourceAsStream(cl, res);
        return is == null ? null : new InputStreamReader(is);
    }

    public static ReadableByteChannel getResourceAsChannel(String res) {
        return getResourceAsChannel(null, res);
    }

    public static ReadableByteChannel getResourceAsChannel(ClassLoader cl, String res) {
        InputStream is = getResourceAsStream(cl, res);
        return null != is ? Channels.newChannel(is) : null;
    }

    /**
     * 返回给定 class 的基本目录在文件系统中的 location
     * <p/>
     * 如果 clazz 在文件系统中则返回 classpath 的标准路径
     * 如果 clazz 在 jar 中, 则返回 jar 在文件系统中的所处目录的标准路径
     * 如果无法获取返回 null
     */
    public static File getClassBaseLocation(Class<?> clazz) {
        CodeSource codeSource = clazz.getProtectionDomain().getCodeSource();
        File loc = null;

        try {
            if (null != codeSource && null != codeSource.getLocation()) {
                loc = new File(codeSource.getLocation().toURI());
            } else {
                String path = clazz.getResource(clazz.getSimpleName() + ".class").getPath();

                int startIndex = path.indexOf(":") + 1;
                int endIndex = path.indexOf("!");
                if ((1 > startIndex) || (endIndex == -1)) {
                    throw new IllegalStateException("Class " + clazz.getSimpleName() + " is located not within a jar: " + path);
                }
                String jarFilePath = path.substring(startIndex, endIndex);
                jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
                loc = new File(jarFilePath).getParentFile();
            }
        } catch (UnsupportedEncodingException ignore) {
        } catch (URISyntaxException ignore) {
        }
        return loc;
    }

    private Resources() {
    }
}
